/**
 * create by zhangpu
 * date:2015年3月12日
 */
package com.acooly.module.openapi.client.provider.yl.marshall;

import com.acooly.core.utils.Reflections;
import com.acooly.core.utils.Strings;
import com.acooly.module.openapi.client.api.anotation.ApiItem;
import com.acooly.module.openapi.client.api.exception.ApiClientException;
import com.acooly.module.openapi.client.api.marshal.ApiUnmarshal;
import com.acooly.module.openapi.client.api.message.MessageFactory;
import com.acooly.module.openapi.client.provider.yl.YlProperties;
import com.acooly.module.openapi.client.provider.yl.domain.YlResponse;
import com.acooly.module.openapi.client.provider.yl.enums.YlServiceEnum;
import com.acooly.module.openapi.client.provider.yl.message.YlbillDownloadResponse;
import com.acooly.module.safety.Safes;
import com.acooly.module.safety.signature.SignTypeEnum;
import com.acooly.module.safety.support.KeyStoreInfo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;

import static com.acooly.module.openapi.client.provider.yl.utils.XmlHelper.parseYlBatchMsgToDto;
import static com.acooly.module.openapi.client.provider.yl.utils.XmlHelper.parseYlQueryMsgToDto;
import static com.acooly.module.openapi.client.provider.yl.utils.XmlHelper.parseYlRealMsgToDto;


/**
 * @author zhangpu
 */
@Slf4j
@Service
public class YlResponseUnmarshall extends YlMarshallSupport implements ApiUnmarshal<YlResponse, String> {

    private static final Logger logger = LoggerFactory.getLogger(YlResponseUnmarshall.class);

    @Resource(name = "ylMessageFactory")
    private MessageFactory messageFactory;

    @Autowired
    protected YlProperties ylProperties;

    @SuppressWarnings("unchecked")
    @Override
    public YlResponse unmarshal(String message, String serviceName) {
        try {
            logger.info("响应报文:{}", message);
            YlResponse ylResponse = (YlResponse) messageFactory.getResponse (serviceName);
            //对帐文件下载单独处理
            if(Strings.equals(YlServiceEnum.YL_BILL_DOWNLOAD.getCode(),serviceName)){
                doFileWriter(message,ylResponse);
                ylResponse.setServiceCode(YlServiceEnum.YL_BILL_DOWNLOAD.code());
                return ylResponse;
            }
            //解析报文
            doUnmarshall(message,ylResponse,serviceName);
            doVerifySign(message,getKeyStoreInfo(ylProperties.getPartnerId()));
            return ylResponse;
        } catch (Exception e) {
            throw new ApiClientException("解析响应报文错误:" + e.getMessage());
        }
    }

    protected YlResponse doUnmarshall(String message, YlResponse response,String serviceName) throws Exception {

        Map<String, Object> messageMap = new HashMap<String, Object>();

        //解析返回的报文
        if(Strings.equals(YlServiceEnum.YL_REAL_DEDUCT.code(),serviceName)){
            parseYlRealMsgToDto(message,messageMap);
            response.setServiceCode(YlServiceEnum.YL_REAL_DEDUCT.code());
        }else if(Strings.equals(YlServiceEnum.YL_REAL_DEDUCT_QUERY.code(),serviceName)){
            parseYlQueryMsgToDto(message,messageMap);
            response.setServiceCode(YlServiceEnum.YL_REAL_DEDUCT_QUERY.code());
        }else if(Strings.equals(YlServiceEnum.YL_BATCH_DEDUCT.code(),serviceName)){
            parseYlBatchMsgToDto(message,messageMap);
        }else if(Strings.equals(YlServiceEnum.YL_BATCH_DEDUCT_QUERY.code(),serviceName)){
            parseYlQueryMsgToDto(message,messageMap);
            response.setServiceCode(YlServiceEnum.YL_BATCH_DEDUCT_QUERY.code());
        }

        Set<Field> fields = Reflections.getFields(response.getClass());
        String key = null;
        for (Field field : fields) {
            ApiItem apiItem = field.getAnnotation(ApiItem.class);
            if (apiItem != null && Strings.isNotBlank(apiItem.value())) {
                key = apiItem.value();
            }else {
                key = field.getName();
            }
            Reflections.invokeSetter(response, field.getName(), messageMap.get(key));
        }
        return response;
    }

    protected void doVerifySign(String message,KeyStoreInfo keyStoreInfo){
        //签名(代收付系统JDK环境使用GBK编码，商户使用签名包时需传送GBK编码集)
        int iStart = message.indexOf("<SIGNED_MSG>");
        if (iStart != -1) {
            int end = message.indexOf("</SIGNED_MSG>");
            String signature = message.substring(iStart+12, end);
            log.info(signature);
            String plain = message.substring(0, iStart) + message.substring(end+13);

            Safes.getSigner(SignTypeEnum.Cert).verify(plain,keyStoreInfo,signature);
        }
    }

    protected void doFileWriter(String message,YlResponse ylResponse){
        FileWriter writer = null;
        File file = null;
        try {
            writer = new FileWriter(ylProperties.getFilePath());
            writer.write(message);
            writer.flush();
            file = new File(ylProperties.getFilePath());
        } catch (IOException e) {
            logger.info("【异常】读写http响应报文发成异常");
            e.printStackTrace();
        } finally {
            if (null != writer) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        YlbillDownloadResponse ylbillDownloadResponse = (YlbillDownloadResponse)ylResponse;
        ylbillDownloadResponse.setFile(file);
    }
}
